package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tianji.learning.enums.LessonStatus.*;
import static com.tianji.learning.enums.PlanStatus.NO_PLAN;
import static com.tianji.learning.enums.PlanStatus.PLAN_RUNNING;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author 东哥
 * @since 2025-06-27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final LearningRecordMapper recordMapper;

    /**
     * 1、添加课程至课程表（Day2 - 随堂1）
     *
     * @param userId
     * @param courseIds
     */
    @Override
    public void addLessons(Long userId, List<Long> courseIds) {
        // 1、根据课程ID集合远程调用 课程微服务，查询课程信息（课程有效月数）
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);
        if (ObjectUtil.isEmpty(courseInfoList)) {
            log.error("课程信息查询失败，courseIds:{}", courseIds);
            return;
        }

        // 2、循环遍历组装课表数据
        List<LearningLesson> lessons = new ArrayList<>(courseInfoList.size());
        for (CourseSimpleInfoDTO courseInfo : courseInfoList) {
            LearningLesson lesson = new LearningLesson();
            // 2.1、填充用户ID和课程ID
            lesson.setUserId(userId);
            lesson.setCourseId(courseInfo.getId());

            // 2.2、计算课程有效期并填充
            Integer validDuration = courseInfo.getValidDuration();
            if (ObjectUtil.isEmpty(validDuration) || validDuration <= 0) {
                continue;
            }
            if (validDuration < 9999) {
                // LocalDateTimeUtil.offset(LocalDateTime.now(), courseInfo.getValidDuration(), ChronoUnit.MONTHS);
                lesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
            }

            // 2.3、添加到集合
            lessons.add(lesson);
        }

        // 3、批量插入课表数据
        this.saveBatch(lessons);
    }

    /**
     * 2、分页查询我的课表（Day2 - 随堂2）
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> pageQueryMyLessons(PageQuery pageQuery) {
        // 1、获取当前登录人ID
        Long userId = UserContext.getUser();

        // 2、发起分页查询
        // select * from learning_lesson where user_id = ? order by latest_learn_time desc limit ?,?
        /*Page<LearningLesson> page = Page.of(pageQuery.getPageNo(),pageQuery.getPageSize());
        if(ObjectUtil.isEmpty(pageQuery.getSortBy())){
            page.addOrder(OrderItem.desc("latest_learn_time"));
        }else{
            page.addOrder(new OrderItem(pageQuery.getSortBy(),pageQuery.getIsAsc()));
        }*/

        Page<LearningLesson> pageResult = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = pageResult.getRecords();
        if (ObjectUtil.isEmpty(records)) {
//             return new PageDTO(pageResult.getTotal(),pageResult.getPages(), Collections.emptyList());
            return PageDTO.empty(pageResult);
        }
//        Page<LearningLesson> page = Page.of(pageQuery.getPageNo(), pageQuery.getPageSize());
//        if (ObjectUtil.isEmpty(pageQuery.getSortBy())){
//            page.addOrder(OrderItem.desc("latest_learn_time"));
//        }else {
//            page.addOrder(new OrderItem(pageQuery.getSortBy(),pageQuery.getIsAsc()));
//        }
//        IPage<LearningLesson> pageResult = this.lambdaQuery()
//                .eq(LearningLesson::getUserId, userId)
//                .page(page);
//        List<LearningLesson> records = pageResult.getRecords();
//        if (ObjectUtil.isEmpty(records)) {
//            return new PageDTO<>(pageResult.getPages(),pageResult.getTotal(),Collections.emptyList());
//        }

        // 3、发起远程调用，查询课程详细信息（课程名称、封面、总章节数）
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = queryCourseInfoAnd2Map(records);


        // 4、循环分页结果，将poList 转为 voList
        List<LearningLessonVO> voList = new ArrayList<>(records.size());
        for (LearningLesson lesson : records) {
            // 4.1、拷贝数据
            LearningLessonVO vo = BeanUtil.toBean(lesson, LearningLessonVO.class);

            // 4.2、填充数据（课程名称、封面、总章节数）
            CourseSimpleInfoDTO courseInfo = courseInfoMap.get(lesson.getCourseId());
            vo.setCourseName(courseInfo.getName());
            vo.setCourseCoverUrl(courseInfo.getCoverUrl());
            vo.setSections(courseInfo.getSectionNum());

            // 4.3、添加到集合
            voList.add(vo);
        }
//        List<LearningLessonVO> voList1 = new ArrayList<>(voList.size());
//        for (LearningLesson record : records) {
//            LearningLessonVO bean = BeanUtil.toBean(record, LearningLessonVO.class);
//            CourseSimpleInfoDTO courseSimpleInfoDTO = courseInfoMap.get(record.getCourseId());
//            bean.setCourseName(courseSimpleInfoDTO.getName());
//            bean.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
//            bean.setSections(courseSimpleInfoDTO.getSectionNum());
//
//            voList1.add(bean);
//        }

        // 5、返回分页结果
        return PageDTO.of(pageResult, voList);
    }

    /**
     * 3、查询我最近正在学习的课程（Day2 - 随堂3）
     *
     * @return
     */
    @Override
    public LearningLessonVO now() {
        // 1、获取当前登录人ID
        Long userId = UserContext.getUser();

        // 2、查询我最近正在学习的课程
        // select * from learning_lesson where user_id = ? and status = 1 order by latest_learn_time desc limit 1
        LearningLesson lesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (ObjectUtil.isEmpty(lesson)) {
            return null;
        }

        // 3、拷贝属性
        LearningLessonVO vo = BeanUtil.toBean(lesson, LearningLessonVO.class);

        // 4、远程调用查询课程信息（名称、封面、小节总数）
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (ObjectUtil.isEmpty(courseInfo)) {
            throw new BizIllegalException("课程信息不存在，无法查询课表");
        }

        // 5、统计课表中该用户的课表数量
        // select count(*) from  learning_lesson where user_id = ?
        Integer count = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
//      Integer count = this.lambdaQuery().eq(LearningLesson::getUserId, userId).count();

        // 6、查询最近学习的小节信息（名称、序号）
        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(List.of(lesson.getLatestSectionId()));
        if (ObjectUtil.isEmpty(cataInfos)) {
            throw new BizIllegalException("小节信息不存在，无法查询课表");
        }

        // 7、补充赋值
        CataSimpleInfoDTO cataInfo = cataInfos.get(0);
        vo.setCourseName(courseInfo.getName());
        vo.setCourseCoverUrl(courseInfo.getCoverUrl());
        vo.setSections(courseInfo.getSectionNum());
        vo.setCourseAmount(count);
        vo.setLatestSectionName(cataInfo.getName());
        vo.setLatestSectionIndex(cataInfo.getCIndex());

        // 8、返回
        return vo;
    }

    private Map<Long, CourseSimpleInfoDTO> queryCourseInfoAnd2Map(List<LearningLesson> records) {
        // 1、获取课程ID集合
        // Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        Set<Long> courseIds = CollStreamUtil.toSet(records, LearningLesson::getCourseId);

        // 2、发起远程调用，查询课程详细信息（课程名称、封面、总章节数）
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);

        // 3、将课程信息转为Map
        // courseInfoList.stream().collect(Collectors.toMap(c -> c.getId(), Function.identity()));
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = CollStreamUtil.toMap(courseInfoList, c -> c.getId(), Function.identity());
        return courseInfoMap;
    }

    /**
     * 4、查询指定课程信息（Day2 - 作业1）
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        // 1.获取当前登录用户
        Long userId = UserContext.getUser();
        // 2.查询课程信息 select * from xx where user_id = #{userId} AND course_id = #{courseId}
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null) {
            return null;
        }
        // 3.处理VO
        return BeanUtils.copyBean(lesson, LearningLessonVO.class);
    }

    /**
     * 5、删除指定课程信息（Day2 - 作业2）
     *
     * @param userId
     */
    @Override
    public void deleteCourseFromLesson(Long userId, List<Long> courseIds) {
        // 1.获取当前登录用户
        if (userId == null) {
            userId = UserContext.getUser();
        }
        // 2.删除课程
        LambdaQueryWrapper<LearningLesson> queryWrapper = Wrappers.lambdaQuery(LearningLesson.class)
                .eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getCourseId, courseIds);
        remove(queryWrapper);
    }

    /**
     * 6、统计课程学习人数（Day2 - 作业3）
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        // select count(1) from xx where course_id = #{cc} AND status in (0, 1, 2)
        return lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus,
                        LessonStatus.NOT_BEGIN.getValue(),
                        LessonStatus.LEARNING.getValue(),
                        LessonStatus.FINISHED.getValue())
                .count();
    }

    /**
     * 7、校验当前课程是否已经报名（Day2 - 作业4）
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        // 2.查询课程
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (lesson == null || LessonStatus.EXPIRED.equals(lesson.getStatus())) {
            return null;
        }
        return lesson.getId();
    }

    /**
     * 8、创建学习计划（Day3 - 随堂3）
     *
     * @param planDTO
     */
    @Override
    public void createPlans(LearningPlanDTO planDTO) {
        // 1、查询课表信息
//        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getCourseId, planDTO.getCourseId())
//                .eq(LearningLesson::getUserId, UserContext.getUser()).one();
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(UserContext.getUser(), planDTO.getCourseId()));
        AssertUtils.isNotNull(lesson, "课程不存在，无法创建学习计划");


        // 2、更新学习计划数据
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(lesson.getPlanStatus() == NO_PLAN, LearningLesson::getPlanStatus, PLAN_RUNNING)
                .eq(LearningLesson::getId, lesson.getId())
                .update();
    }

    private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        return queryWrapper;
    }

    /**
     * 9、统计查询我的学习计划（Day3 - 随堂4）
     *
     * @param pageQuery
     * @return
     */
    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery pageQuery) {
        LearningPlanPageVO vo = new LearningPlanPageVO();
        // 1、获取当前登录人ID
        Long userId = UserContext.getUser();

        // 2、分页查询我的课表（我的、制定过学习计划、课表状态不为失效的
        // SELECT * FROM learning_lesson WHERE user_id = 2 AND plan_status = 1 AND `status` IN (0,1,2) limit ?,?
        Page<LearningLesson> pageResult = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PLAN_RUNNING)
                .in(LearningLesson::getStatus, NOT_BEGIN, LEARNING, FINISHED)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = pageResult.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return vo.emptyPage(pageResult);
        }

        // 3、收集课程ID，根据课程ID集合远程调用查询课程信息
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = queryCourseInfoAnd2Map(records);

        // 4、统计本周实际学习小节数量
        // select lesson_id,count(1) num from `learning_record` where user_id = 2 and finished = 1
        // and finish_time between '2025-06-23 00:00:00' and '2025-06-29 23:59:59' GROUP BY lesson_id
        // 4.1、获取本周开始、结束日期
        LocalDateTime begin = DateUtils.getWeekBeginTime(LocalDate.now());
        LocalDateTime end = DateUtils.getWeekEndTime(LocalDate.now());

        // 4.2、发起分组统计
        QueryWrapper<LearningRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("lesson_id", "count(1) num")
                .eq("user_id", userId)
                .eq("finished", true)
                .between("finish_time", begin, end)
                .groupBy("lesson_id");
        List<Map<String, Object>> mapList = this.recordMapper.selectMaps(queryWrapper);
        // mapList
        //     Map1
        //         "lesson_id" : 97787237823
        //         "num" ： 5
        //     Map2
        //         "lesson_id" : 88123123222
        //         "num" ： 2
        Map<Long, Long> learnedSectionNumMap = mapList.stream().collect(Collectors.toMap(
                m -> (Long) m.get("lesson_id"), m -> (Long) m.get("num")
        ));

        // 5、循环分页课表数据，封装填充缺失数据
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson lesson : records) {
            // 5.1、拷贝数据
            LearningPlanVO learningPlanVo = BeanUtil.toBean(lesson, LearningPlanVO.class);

            // 5.2、填充课程数据
            CourseSimpleInfoDTO courseInfo = courseInfoMap.get(lesson.getCourseId());
            if (ObjectUtil.isNotEmpty(courseInfo)) {
                learningPlanVo.setCourseName(courseInfo.getName());
                learningPlanVo.setSections(courseInfo.getSectionNum());
            }

            // 5.3、填充本周已学习小节数
            learningPlanVo.setWeekLearnedSections(learnedSectionNumMap.getOrDefault(lesson.getId(),0L).intValue());

            // 5.4、添加到集合
            voList.add(learningPlanVo);
        }

        // 6、计算 本周已学习小节总数量
        long sum = learnedSectionNumMap.values().stream().mapToLong(Long::longValue).sum();

        // 7、计算 本周计划学习的总小节数
        // SELECT sum(week_freq) total_weekfreq FROM learning_lesson WHERE user_id = 2 AND plan_status = 1 AND `status` IN (0,1,2)
        LearningLesson lesson = this.query()
                .select("sum(week_freq) as total_weekfreq")
                .eq("user_id", userId)
                .eq("plan_status", PLAN_RUNNING)
                .in("status", NOT_BEGIN, LEARNING, FINISHED).one();

        // 8、封装数据并返回
        vo.setWeekFinished(Long.valueOf(sum).intValue());
        vo.setWeekTotalPlan(lesson.getTotalWeekfreq());
        vo.pageInfo(pageResult.getTotal(),pageResult.getPages(), voList);
        return vo;
    }


}
